#pragma once
#include<thread>
#include<mutex>
#include<condition_variable>
#include "EventLoop_Timequeue.hpp"

class LoopThread {
    private:
        std::thread _thread;//
        EventLoop* _loop;// EventLoop指针变量，这个对象需要在线程内实例化
        std::mutex _mutex;//互斥锁
        std::condition_variable _cond;//条件变量，⽤于实现_loop获取的同步关系，避免线程创建了，但是_loop还没有实例化之前去获取_loop
    private:
        // 线程入口函数，在线程内实例化 EventLoop 对象，唤醒_cond上有可能阻塞的线程，并且开始运⾏EventLoop模块的功能
        void Entry()
        {
            {
                std::unique_lock<std::mutex> lock(_mutex);//加锁
                _loop = new EventLoop();//实例化 EventLoop 对象
                _cond.notify_all();//唤醒_cond上有可能阻塞的线程
            }
            _loop->Start();
        }
    public:
        LoopThread()
            : _loop(nullptr)
            ,_thread(&LoopThread::Entry, this)/*创建线程，设定线程⼊⼝函数*/
        {}
        EventLoop *GetLoop()
        {
            {
                std::unique_lock<std::mutex> lock(_mutex);//加锁
                _cond.wait(lock, [this] { return _loop != nullptr; });//等待_loop实例化完成
            }
            return _loop;//返回EventLoop指针
        }

};

//线程池，生成一定数量的LoopThread线程
class ThreadPool {
    private:
        int _thread_num;//线程数量
        int _index = 0;//线程索引(在vector中的索引)，用于循环分配EventLoop对象管理Connection
        EventLoop* _base_loop;//
        std::vector<LoopThread*> _threads;//线程池
        std::vector<EventLoop*> _loops;//EventLoop指针数组，每个线程对应一个EventLoop对象
    public:
        ThreadPool(EventLoop* base_loop, int thread_num = 0)
            : _base_loop(base_loop)
           , _thread_num(thread_num)
        {}
        void SetThreadNum(int num){ _thread_num = num; }
        void BulidPools()
        {
            if(_thread_num > 0){
                _threads.resize(_thread_num);
                _loops.resize(_thread_num);
                for(int i = 0; i < _thread_num; ++i){
                    _threads[i] = new LoopThread();
                    _loops[i] = _threads[i]->GetLoop();
                    LOG_DBG("build thread %d",i);
                }
            }
            return ;
        }
        EventLoop* NextLoop()
        {
            if(_thread_num == 0){
                return _base_loop;
            }
            _index = (_index + 1) % _thread_num;
            return _loops[_index];
        }
};